package cn.smartaccount.demo.common.util;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.FastDateFormat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Map;
import java.util.TimeZone;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author xuluquan
 * @date 2021-07-07 15:09
 */
public class DateUtil {

    private static final Logger logger = LoggerFactory.getLogger(DateUtil.class);
    private static final FastDateFormat dateFormatYYMMDD = createDateFormat("yyyy-MM-dd");
    private static final FastDateFormat formatYYMMDD = createDateFormat("yyyyMMdd");
    private static final FastDateFormat datetimeFormat = createDateFormat("yyyy-MM-dd HH:mm:ss");
    private static final FastDateFormat formatHHmmss = createDateFormat("HH:mm:ss");
    private static final FastDateFormat yyyyMMddHHmmssSSS = createDateFormat("yyyyMMddHHmmssSSS");
    private static final FastDateFormat yyyyMMddHHmmss = createDateFormat("yyyyMMddHHmmss");
    private static final FastDateFormat formateHHmmss = createDateFormat("HHmmss");
    private static final FastDateFormat dateHoursFormat = createDateFormat("HH");
    private static Map<String, FastDateFormat> timeZoneMap = new ConcurrentHashMap<>();

    public static FastDateFormat createDateFormat(String pattern) {
        return FastDateFormat.getInstance(pattern, TimeZone.getTimeZone("GMT+8"));
    }

    private static FastDateFormat getDateFormat(String pattern, TimeZone timeZone) {
        String zoneId = timeZone.getID();
        FastDateFormat timeZoneFormat = (FastDateFormat) timeZoneMap.get(zoneId);
        if (timeZoneFormat == null) {
            timeZoneFormat = FastDateFormat.getInstance(pattern, timeZone);
            timeZoneMap.put(zoneId, timeZoneFormat);
        }

        return timeZoneFormat;
    }

    public static Date parseDate(Object value) {
        if (null == value) {
            return null;
        }
        if (value instanceof Date) {
            return (Date) value;
        } else if (value instanceof Long) {
            return new Date((long) value);
        } else if (StringUtils.isNumeric(value.toString())) {
            return new Date(Long.parseLong(value.toString()));
        } else {
            try {
                return parseDateTime(value.toString());
            } catch (ParseException e) {
                return null;
            }
        }
    }

    public static Date parseDateTime(String source) throws ParseException {
        return datetimeFormat.parse(source);
    }

    public static Date parseDateTime(String source, TimeZone timeZone) throws ParseException {
        if (timeZone != null) {
            FastDateFormat format = getDateFormat("yyyy-MM-dd HH:mm:ss", timeZone);
            return format.parse(source);
        } else {
            return datetimeFormat.parse(source);
        }
    }

    public static Date parse(long timestamp) {
        return new Date(timestamp);
    }

    public static Long parseLong(Object obj) {
        if (obj instanceof Long) {
            return (Long) obj;
        } else if (obj instanceof Date) {
            return ((Date) obj).getTime();
        } else if (null == obj) {
            return null;
        } else {
            String dateStr = obj.toString();

            try {
                return dateStr.contains("-") ? parseDateTime(dateStr).getTime() : Long.parseLong(dateStr);
            } catch (Exception var3) {
                logger.error(var3.getMessage(), var3);
                return null;
            }
        }
    }

    public static String formatDateYYMMDD(Date date) {
        return dateFormatYYMMDD.format(date);
    }

    public static Date atStartOfDay(Date date) {
        try {
            return parseDateTime(dateFormatYYMMDD.format(date) + " 00:00:00");
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }

    public static Long atStartOfDayToMil(Date date) {
        return atStartOfDay(new Date()).getTime();
    }

    public static String formatYYMMDD(Date date) {
        return formatYYMMDD.format(date);
    }

    public static String formatHHmmss(Date date) {
        return formatHHmmss.format(date);
    }

    public static String formatDateYYMMDD(long timestamp) {
        return dateFormatYYMMDD.format(timestamp);
    }

    public static String formatYyyyMMddHHmmss(Date date) {
        return yyyyMMddHHmmss.format(date);
    }

    public static String formateHHmmss(Date date) {
        return formateHHmmss.format(date);
    }

    public static String formatHour(Date date) {
        return dateHoursFormat.format(date);
    }

    public static String formatDate(String source) throws ParseException {
        return formatDateYYMMDD(parseDateTime(source));
    }

    public static String formatDateTime(Date date) {
        return datetimeFormat.format(date);
    }

    public static String formatDateTime(long timestamp) {
        return datetimeFormat.format(timestamp);
    }

    public static String formatDateTime(String source) throws ParseException {
        return formatDateTime(parseDate(source));
    }

    public static int compare(String arg1, String arg2) throws ParseException {
        try {
            return parseDateTime(arg1).compareTo(parseDateTime(arg2));
        } catch (ParseException var3) {
            return parseDate(arg1).compareTo(parseDate(arg2));
        }
    }

    public static String getTimeStampString() {
        return yyyyMMddHHmmssSSS.format(System.currentTimeMillis());
    }

    public static Timestamp formatTimestampString(String dateStr) {
        Calendar c = Calendar.getInstance();
        long time = 4133865600000L;
        c.setTimeInMillis(time);
        if (dateStr == null) {
            return new Timestamp(c.getTimeInMillis());
        } else {
            return new Timestamp(parseDate(dateStr).getTime());
        }
    }

    public static long floorDay(long day) {
        Calendar c = Calendar.getInstance();
        c.setTimeInMillis(day);
        c.set(11, 0);
        c.set(12, 0);
        c.set(13, 0);
        c.set(14, 0);
        return c.getTime().getTime();
    }

    public static final long MI_SEC_IN_DAY = 86400000L;
    public static final String DEFAULT_DATE_FMT = "yyyy-MM-dd HH:mm:ss";

    public static Date currentDate() {
        return new Date();
    }

    public static int diffDays(Date date1, Date date2) {
        return date2 != null && date1 != null ? (int) ((date1.getTime() - date2.getTime()) / 86400000L) : 0;
    }

    public static String formatDate(Object date, String fmt) {
        if (date == null) {
            return null;
        } else if (!(date instanceof Date)) {
            return date.toString();
        } else {
            SimpleDateFormat sdf = new SimpleDateFormat(fmt);
            return sdf.format(date);
        }
    }

    public static Date parseDate(String date) {
        return parseDate(date, "yyyy-MM-dd HH:mm:ss");
    }

    public static Date parseDate(String date, String fmt) {
        if (date == null) {
            return null;
        } else {
            SimpleDateFormat sdf = new SimpleDateFormat(fmt);

            try {
                return sdf.parse(date);
            } catch (ParseException var4) {
                return null;
            }
        }
    }

    public static String formatNow(String fmt) {
        return formatDate(new Date(), fmt);
    }

    public static String formatFullDate(Object date) {
        return formatDate(date, "yyyy-MM-dd HH:mm:ss");
    }

    public static String formatDateYMD(Object date) {
        return formatDate(date, "yyyy-MM-dd");
    }

    public static Date addMinute(Date date, int minute) {
        if (date == null) {
            return null;
        } else {
            Calendar cal = Calendar.getInstance();
            cal.setTime(date);
            cal.add(12, minute);
            return cal.getTime();
        }
    }

    public static Date addSecond(Date date, int second) {
        if (date == null) {
            return null;
        } else {
            Calendar cal = Calendar.getInstance();
            cal.setTime(date);
            cal.add(13, second);
            return cal.getTime();
        }
    }

    public static Date addHour(Date date, int hour) {
        if (date == null) {
            return null;
        } else {
            Calendar cal = Calendar.getInstance();
            cal.setTime(date);
            cal.add(11, hour);
            return cal.getTime();
        }
    }

    public static Date addDay(Date date, int days) {
        if (date == null) {
            return null;
        } else {
            Calendar cal = Calendar.getInstance();
            cal.setTime(date);
            cal.add(6, days);
            return cal.getTime();
        }
    }

    public static Date addMonth(Date date, int months) {
        if (date == null) {
            return null;
        } else {
            Calendar cal = Calendar.getInstance();
            cal.setTime(date);
            cal.add(2, months);
            return cal.getTime();
        }
    }

    public static Calendar toCalendar(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal;
    }

    public static boolean isSameDay(Date date1, Date date2) {
        return isSameDay(toCalendar(date1), toCalendar(date2));
    }

    public static Date getDayYMD(Date date) {
        if (date == null) {
            return null;
        } else {
            Calendar cal = Calendar.getInstance();
            cal.setTime(date);
            cal.set(11, 0);
            cal.set(12, 0);
            cal.set(13, 0);
            cal.set(14, 0);
            return cal.getTime();
        }
    }

    public static int getHour(Date date) {
        Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT+8"));
        cal.setTime(date);
        return cal.get(11);
    }

    public static int getMinute(Date date) {
        Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT+8"));
        cal.setTime(date);
        return cal.get(12);
    }

    public static int getSecond(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal.get(13);
    }

    public static boolean isDateAfter(Date d1, Date d2) {
        return d1.getTime() > d2.getTime();
    }

    public static boolean isSameDay(Calendar cal1, Calendar cal2) {
        int year1 = cal1.get(1);
        int day1 = cal1.get(6);
        int year2 = cal2.get(1);
        int day2 = cal2.get(6);
        return year1 != year2 ? false : day1 == day2;
    }

    public static boolean validateString(String dateString, String dateFormat) {
        if (StringUtils.isNotEmpty(dateString) && StringUtils.isNotEmpty(dateFormat)) {
            Pattern pattern = Pattern.compile(dateFormat);
            Matcher matcher = pattern.matcher(dateString);
            return matcher.find();
        } else {
            return false;
        }
    }

}
